package com.coldworks.coldjoke.manager;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import android.content.Context;
import android.os.AsyncTask;
import android.os.AsyncTask.Status;
import android.util.Pair;

import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.coldworks.base.manager.BaseBitmapManager;
import com.coldworks.base.manager.BaseNetworkManager;
import com.coldworks.base.manager.BaseStorageManager;
import com.coldworks.coldjoke.model.JokeEntity;
import com.coldworks.coldjoke.model.JokeModel;
import com.coldworks.coldjoke.util.CONST;
import com.coldworks.coldjoke.util.JsonUtil;
import com.coldworks.coldjoke.util.NetworkUtil;

public class JokeManager {
	protected final Logger log = LoggerFactory.getLogger(this.getClass());

	private static int THUMBNAILWIDTH = 200;
	private static int THUMBNAILHEIGHT = 150;

	private static int DEFAULTLIMIT = 10;
	private static int LOCALLIMIT = 50;

	public static final int GET_JOKE_NEW_SUCC = 6;

	private List<JokeModel> listShow;
	private List<JokeModel> listNext;
	private Map<String, JokeModel> dictLocal;
	private HashSet<String> setShow;

	private JokeInitTask jokeInitTask;
	private JokeStartTask jokeStartTask;
	private JokeNewTask jokeNewTask;
	private JokeNextTask jokeNextTask;
	private int backIndex = 0;

	private boolean started;

	private Context context;
	// 不同到列别NEW出来到是不同的
	private String jokesType;
	private String jokesSort;
	private String jokesInterval;
	private boolean dbUsed;
	private JokeEntity jokeEntity;
	private JokeManagerDelegate delegate;

	public JokeManager(Context context, JokeEntity jokeEntity,
			String jokesSort, String jokesInterval, String jokesType) {
		this.context = context;
		this.jokeEntity = jokeEntity;
		this.listNext = new ArrayList<JokeModel>();
		this.listShow = new ArrayList<JokeModel>();
		this.setShow = new HashSet<String>();
		this.dictLocal = new HashMap<String, JokeModel>();
		this.jokesInterval = jokesInterval;
		this.jokesSort = jokesSort;
		this.jokesType = jokesType;
		this.dbUsed = false;
		this.started = false;
	}

	// init用来初始化数据 返回值来判断数据库是否有数据
	public void init(JokeManagerDelegate delegate) {
		this.delegate = delegate;
		if (JokeDbManager.getInstance().openJokeDb(context)) {
			dbUsed = true;
			JokeDbManager.getInstance().createJokeDb(context, jokesSort);
			// 获取整个DB的列表，便于比较
			List<JokeModel> listAll = JokeDbManager.getInstance()
					.getAllJokeSummary(context, jokesSort);
			List<String> ids2Del = new ArrayList<String>();
			int count = 0;
			for (int index = 0; index < listAll.size(); ++index) {
				JokeModel one = listAll.get(index);
				if (++count <= LOCALLIMIT) {
					dictLocal.put(one.getJokeId(), one);
					listShow.add(one);
					setShow.add(one.getJokeId());
				} else {
					ids2Del.add(one.getJokeId());
				}
			}
			if (ids2Del.size() > 0) {
				JokeDbManager.getInstance().deleteJokes(context, jokesSort,
						ids2Del);
			}
			log.info("local(" + jokesSort + "): all/del/left : "
					+ listAll.size() + "/" + ids2Del.size() + "/"
					+ listShow.size());
			listAll.clear();
			ids2Del.clear();
		} else {
			dbUsed = false;
		}
	}

	public boolean isDbUsed() {
		return dbUsed;
	}

	// 获取当前需要展示的
	public List<JokeModel> getListShow() {
		return listShow;
	}

	public void removeLikeState() {
		for (JokeModel one : dictLocal.values()) {
			one.setLiked(-1);
			one.setDisliked(-1);
		}
		JokeDbManager.getInstance().removeLikeState(context, jokesSort);
	}

	public boolean isGettingNew() {
		return jokeNewTask != null
				&& jokeNewTask.getStatus() != Status.FINISHED;
	}

	private boolean isGettingNext() {
		return jokeNextTask != null
				&& jokeNextTask.getStatus() != Status.FINISHED;
	}

	public boolean getStart() {
		if (started) {
			return false;
		}
		started = true;
		if (getListShow().size() == 0) {
			jokeInitTask = new JokeInitTask();
			jokeInitTask.execute();
		} else {
			jokeStartTask = new JokeStartTask();
			jokeStartTask.execute();
		}
		return true;
	}

	public void getNew() {
		if (isGettingNew()) {
			return;
		}
		jokeNewTask = new JokeNewTask();
		jokeNewTask.execute();
	}

	public void getNext() {
		if (isGettingNext()) {
			jokeNextTask.setContinue(true);
			return;
		}
		// 把listNext中的数据合并到listShow中
		// 并异步触发prepareNext
		int nextCount = 0;
		for (JokeModel one : listNext) {
			if (setShow.contains(one.getJokeId())) {
				continue;
			}
			listShow.add(one);
			setShow.add(one.getJokeId());
			nextCount++;
		}
		listNext.clear();
		delegate.JMloadNext(jokeEntity, nextCount);
		jokeNextTask = new JokeNextTask();
		jokeNextTask.execute();
	}

	public void getNewAndNext() {
		if (isGettingNew()) {
			return;
		}
		new JokeNewAndNextTask().execute();
	}

	public interface JokeManagerDelegate {
		void JMloadNew(JokeEntity jokeEntity, int newCount);

		void JMloadNext(JokeEntity jokeEntity, int nextCount);

		void JMloadNewAndNext(JokeEntity jokeEntity, int newCount, int nextCount);
	}

	protected List<JokeModel> expJokes(String url) {
		List<JokeModel> res = new ArrayList<JokeModel>();
		DefaultHttpClient httpclient;
		HttpGet get = new HttpGet(url);
		httpclient = BaseNetworkManager.getInstance().createHttpClient(context);
		try {
			String sessionId = UserManager.getInstance().getSessionId();
			get.setHeader("COOKIE", "webpy_session_id=" + sessionId);
			HttpResponse response = httpclient.execute(get);
			if (response.getStatusLine().getStatusCode() == 200) {
				Header contentEncoding = response
						.getFirstHeader("Content-Encoding");
				JSONObject jsonObject = null;
				if (contentEncoding != null
						&& contentEncoding.getValue().equalsIgnoreCase("gzip")) {
					jsonObject = NetworkUtil.getInstance().getJsonObjectByGzip(
							response.getEntity().getContent());
				} else {
					jsonObject = NetworkUtil.getInstance().getJSONObject(
							response.getEntity().getContent());
				}
				if (jsonObject == null) {
					log.info("error-->json=null");
					return res;
				}
				res = JsonUtil.getJokeInfoList(jsonObject);
			} else {
				log.info(String.valueOf(response.getStatusLine()
						.getStatusCode()));
				return res;
			}
		} catch (Exception e) {
			log.error("", e);
		} finally {
		}
		return res;
	}

	public boolean saveFullJoke(JokeModel pJoke) {
		boolean res = false;
		JokeModel tmp = new JokeModel(pJoke);
		if (!tmp.getImgUrl().equals("")) {
			File dir = BaseStorageManager.getInstance().getImgDir();
			if (dir == null) {
				return false;
			}
			File file = new File(dir
					+ BaseBitmapManager.getInstance().getFileNameByUrl(
							tmp.getImgUrl()));
			res = BaseBitmapManager.getInstance().downBitmapByUrl(context,
					tmp.getImgUrl(), file);
			if (res) {
				pJoke.setImgPath(file.getAbsolutePath());
				tmp.setImgPath(file.getAbsolutePath());
				tmp.setThumb(BaseBitmapManager.getInstance()
						.getThumbnailByPath(context, file.getAbsolutePath(),
								THUMBNAILWIDTH, THUMBNAILHEIGHT));
			}
		} else {
			res = true;
		}
		if (res) {
			res = JokeDbManager.getInstance().saveOneJoke(context, jokesSort, tmp);
			tmp.clearThumb();
		}
		return res;
	}

	public List<JokeModel> merge(int startIndex, List<JokeModel> listHttp) {
		List<JokeModel> res = new ArrayList<JokeModel>();
		int index = startIndex;
		int count = listHttp.size() + startIndex - 1;
		for (JokeModel one : listHttp) {
			JokeModel hit = dictLocal.get(one.getJokeId());
			if (hit == null) { // 本地不含
				boolean oneNewSaved = false;
				one.setJokeIndex(index);
				log.info("type:" + jokesSort + " (" + one.getJokeIndex() + "/"
						+ count + ") loading : " + one.getJokeId() + " - "
						+ (one.getImgUrl().equals("") ? "noImg" : "Img"));
				oneNewSaved = saveFullJoke(one);
				if (oneNewSaved) {
					// log.info("type:" + jokesSort + " (" + one.getJokeIndex()
					// + "/"
					// + count
					// + ") loading : " + one.getJokeId() + " done");
					dictLocal.put(one.getJokeId(), one);
					res.add(one);
					++index;
				} else {
					log.info("type:" + jokesSort + " (" + one.getJokeIndex()
							+ "/" + count + ") loading : failed");
				}
			} else { // 本地已经存在
				boolean changed = false;
				if (hit.getJokeIndex() != index) {
					hit.setJokeIndex(index);
					changed = true;
				}
				if (hit.getGoodNum() != one.getGoodNum()) {
					hit.setGoodNum(one.getGoodNum());
					changed = true;
				}
				if (hit.getBadNum() != one.getBadNum()) {
					hit.setBadNum(one.getBadNum());
					changed = true;
				}
				if (hit.getReplyNum() != one.getReplyNum()) {
					hit.setReplyNum(one.getReplyNum());
					changed = true;
				}
				if (changed) {
					JokeDbManager.getInstance().updateOneJoke(context, jokesSort,
							hit);
				}
				res.add(hit);
				log.info("type:" + jokesSort + " (" + hit.getJokeIndex() + "/"
						+ count + ") exist : " + hit.getJokeId());
				++index;
			}
		}
		return res;
	}

	public class JokeInitTask extends AsyncTask<Void, Integer, Integer> {
		@Override
		protected Integer doInBackground(Void... params) {
			try {
				int tIndex = listShow.size();
				if (tIndex == 0) {
					tIndex = DEFAULTLIMIT;
				}
				String url;
				if (jokesInterval == null) {
					url = CONST.URL.JOKE + "?action=getJokes&sort=" + jokesSort
							+ "&start=0&limit=" + tIndex + "&type=" + jokesType;
				} else {
					url = CONST.URL.JOKE + "?action=getJokes&sort=" + jokesSort
							+ "&start=0&limit=" + tIndex + "&type=" + jokesType
							+ "&interval=" + jokesInterval;
				}
				int newCount = 0;
				List<JokeModel> listHttp = expJokes(url);
				backIndex += listHttp.size();
				for (JokeModel one : listHttp) {
					boolean oneNewSaved = false;
					one.setJokeIndex(newCount);
					log.info("(" + jokesSort + ":" + one.getJokeIndex() + "/"
							+ (listHttp.size() - 1) + ") loading : "
							+ one.getJokeId() + " - " + one.getImgUrl());
					oneNewSaved = saveFullJoke(one);
					if (oneNewSaved) {
						log.info("(" + jokesSort + ":" + one.getJokeIndex()
								+ "/" + (listHttp.size() - 1)
								+ ") loading : done");
						dictLocal.put(one.getJokeId(), one);
						listShow.add(one);
						setShow.add(one.getJokeId());
						++newCount;
						publishProgress(newCount);
					} else {
						log.info("(" + jokesSort + ":" + one.getJokeIndex()
								+ "/" + (listHttp.size() - 1)
								+ ") loading : failed");
					}
				}
				return newCount;
			} catch (Exception e) {
				log.error("", e);
				return 0;
			}
		}

		@Override
		protected void onProgressUpdate(Integer... values) {
			super.onProgressUpdate(values);
			delegate.JMloadNext(jokeEntity, 1);
		}

		@Override
		protected void onPostExecute(Integer result) {
			super.onPostExecute(result);
			if (result > 0) {
				delegate.JMloadNew(jokeEntity, result);
			}
			delegate.JMloadNew(jokeEntity, 0);
			jokeNextTask = new JokeNextTask();
			jokeNextTask.execute();
		}
	}

	public class JokeStartTask extends AsyncTask<Void, Integer, Integer> {
		@Override
		protected Integer doInBackground(Void... params) {
			try {
				int tIndex = listShow.size();
				if (tIndex == 0) {
					tIndex = DEFAULTLIMIT;
				}
				String url;
				if (jokesInterval == null) {
					url = CONST.URL.JOKE + "?action=getJokes&sort=" + jokesSort
							+ "&start=0&limit=" + tIndex + "&type=" + jokesType;
				} else {
					url = CONST.URL.JOKE + "?action=getJokes&sort=" + jokesSort
							+ "&start=0&limit=" + tIndex + "&type=" + jokesType
							+ "&interval=" + jokesInterval;
				}
				List<JokeModel> listHttp = expJokes(url);
				backIndex += listHttp.size();
				Set<String> setHttp = new HashSet<String>();
				for (JokeModel one : listHttp) {
					setHttp.add(one.getJokeId());
				}
				int newCount = listHttp.size();
				for (JokeModel one : listShow) {
					if (!setHttp.contains(one.getJokeId())) { // 显示列表中不含
						JokeModel tmp = new JokeModel(one);
						listHttp.add(tmp);
						setHttp.add(tmp.getJokeId());
					} else {
						newCount--;
					}
				}

				List<JokeModel> listNew = merge(0, listHttp);

				listShow.clear();
				setShow.clear();
				for (JokeModel one : listNew) {
					listShow.add(one);
					setShow.add(one.getJokeId());
				}

				int startIndex = listShow.size();
				List<JokeModel> newListNext = new ArrayList<JokeModel>();
				for (JokeModel one : listNext) {
					if (!setShow.contains(one.getJokeId())) {
						boolean changed = false;
						if (one.getJokeIndex() != startIndex) {
							one.setJokeIndex(startIndex);
							changed = true;
						}
						if (changed) {
							JokeDbManager.getInstance().updateOneJoke(context,
									jokesSort, one);
						}
						newListNext.add(one);
						startIndex++;
					}
				}
				listNext.clear();
				listNext = newListNext;
				listHttp.clear();
				setHttp.clear();
				listNew.clear();
				return newCount;
			} catch (Exception e) {
				log.error("", e);
				return 0;
			}
		}

		@Override
		protected void onPostExecute(Integer result) {
			super.onPostExecute(result);
			if (result > 0) {
				delegate.JMloadNew(jokeEntity, result);
			}
			delegate.JMloadNew(jokeEntity, 0);
			jokeNextTask = new JokeNextTask();
			jokeNextTask.execute();
		}
	}

	public class JokeNewTask extends AsyncTask<Void, Integer, Integer> {
		public Integer doJokeNewTask() {
			try {
				int tIndex = listShow.size();
				if (tIndex == 0) {
					tIndex = DEFAULTLIMIT;
				}
				if (tIndex > LOCALLIMIT) {
					tIndex = LOCALLIMIT;
				}
				String url;
				if (jokesInterval == null) {
					url = CONST.URL.JOKE + "?action=getJokes&sort=" + jokesSort
							+ "&start=0&limit=" + tIndex + "&type=" + jokesType;
				} else {
					url = CONST.URL.JOKE + "?action=getJokes&sort=" + jokesSort
							+ "&start=0&limit=" + tIndex + "&type=" + jokesType
							+ "&interval=" + jokesInterval;
				}
				List<JokeModel> listHttp = expJokes(url);
				Set<String> setHttp = new HashSet<String>();
				for (JokeModel one : listHttp) {
					setHttp.add(one.getJokeId());
				}
				int newCount = listHttp.size();
				for (JokeModel one : listShow) {
					if (!setHttp.contains(one.getJokeId())) { // 显示列表中不含
						JokeModel tmp = new JokeModel(one);
						listHttp.add(tmp);
						setHttp.add(tmp.getJokeId());
					} else {
						newCount--;
					}
				}

				List<JokeModel> listNew = merge(0, listHttp);

				listShow.clear();
				setShow.clear();
				for (JokeModel one : listNew) {
					listShow.add(one);
					setShow.add(one.getJokeId());
				}

				int startIndex = listShow.size();
				List<JokeModel> newListNext = new ArrayList<JokeModel>();
				for (JokeModel one : listNext) {
					if (!setShow.contains(one.getJokeId())) {
						boolean changed = false;
						if (one.getJokeIndex() != startIndex) {
							one.setJokeIndex(startIndex);
							changed = true;
						}
						if (changed) {
							JokeDbManager.getInstance().updateOneJoke(context,
									jokesSort, one);
						}
						newListNext.add(one);
						startIndex++;
					}
				}
				listNext.clear();
				listNext = newListNext;
				listHttp.clear();
				setHttp.clear();
				listNew.clear();
				return newCount;
			} catch (Exception e) {
				log.error("", e);
				return 0;
			}
		}

		@Override
		protected Integer doInBackground(Void... params) {
			return doJokeNewTask();
		}

		@Override
		protected void onPostExecute(Integer result) {
			super.onPostExecute(result);
			if (result > 0) {
				delegate.JMloadNew(jokeEntity, result);
			}
			jokeNewTask = null;
			delegate.JMloadNew(jokeEntity, 0);
		}
	}

	public class JokeNextTask extends AsyncTask<Void, Integer, Integer> {
		private boolean continueAfterLoaded = false;

		public void setContinue(boolean continueAfterLoaded) {
			this.continueAfterLoaded = continueAfterLoaded;
		}

		public Integer doJokeNextTask() {
			try {
				int tIndex = listShow.size();
				if (tIndex == 0) {
					tIndex = DEFAULTLIMIT;
				}
				String url;
				if (jokesInterval == null) {
					url = CONST.URL.JOKE + "?action=getJokes&sort=" + jokesSort
							+ "&start=" + backIndex + "&limit=" + DEFAULTLIMIT
							+ "&type=" + jokesType;
				} else {
					url = CONST.URL.JOKE + "?action=getJokes&sort=" + jokesSort
							+ "&start=" + backIndex + "&limit=" + DEFAULTLIMIT
							+ "&type=" + jokesType + "&interval="
							+ jokesInterval;
				}
				// log.info(url);

				List<JokeModel> listHttp = expJokes(url);
				backIndex += listHttp.size();

				int lastIndex = 0;
				if (listShow.size() > 0) {
					lastIndex = listShow.get(listShow.size() - 1)
							.getJokeIndex() + 1;
				}

				List<JokeModel> tListNext = merge(lastIndex, listHttp);

				int nextCount = 0;
				for (JokeModel one : tListNext) {
					if (!setShow.contains(one.getJokeId())) {
						listNext.add(one);
						nextCount++;
					}
				}

				listHttp.clear();
				tListNext.clear();
				return nextCount;
			} catch (Exception e) {
				log.error("", e);
				return 0;
			}
		}

		@Override
		protected Integer doInBackground(Void... params) {
			return doJokeNextTask();
		}

		@Override
		protected void onPostExecute(Integer result) {
			super.onPostExecute(result);
			jokeNextTask = null;
			if (!continueAfterLoaded) {
				return;
			}
			continueAfterLoaded = false;
			int nextCount = 0;
			for (JokeModel one : listNext) {
				if (setShow.contains(one.getJokeId())) {
					continue;
				}
				listShow.add(one);
				setShow.add(one.getJokeId());
				nextCount++;
			}
			listNext.clear();
			delegate.JMloadNext(jokeEntity, nextCount);
			jokeNextTask = new JokeNextTask();
			jokeNextTask.execute();
		}
	}

	public class JokeNewAndNextTask extends
			AsyncTask<Void, Integer, Pair<Integer, Integer>> {

		@Override
		protected Pair<Integer, Integer> doInBackground(Void... params) {
			jokeNewTask = new JokeNewTask();
			int newCount = jokeNewTask.doJokeNewTask();

			int nextCount = 0;
			for (JokeModel one : listNext) {
				if (setShow.contains(one.getJokeId())) {
					continue;
				}
				listShow.add(one);
				setShow.add(one.getJokeId());
				nextCount++;
			}
			listNext.clear();
			log.info("new : " + newCount + ", next :" + nextCount);
			return new Pair<Integer, Integer>(newCount, nextCount);
		}

		@Override
		protected void onPostExecute(Pair<Integer, Integer> result) {
			jokeNewTask = null;
			delegate.JMloadNewAndNext(jokeEntity, result.first, result.second);
			if (!isGettingNext()) {
				jokeNextTask = new JokeNextTask();
				jokeNextTask.execute();
			}
		}
	}

	public String getJokesSort() {
		return jokesSort;
	}
}
